<?php
/**
 * licenses : MIT
 * creatTime: 2020/5/13
 * author : weblinuxgame
 * filename: Result.php
 */

namespace App\Core\Utils;

use Illuminate\Support\Arr;
use App\Core\Interfaces\ResultInterface;
use Illuminate\Contracts\Support\Arrayable;
use Throwable;


/**
 * 结果对象
 * Class Result
 * @package App\Core\Utils
 */
class Result implements ResultInterface
{
    protected $code;
    protected $message;
    protected $data;

    public function __construct($data = [], $message = '', $code = 0)
    {
        $this->data = $data;
        $this->message = $message;
        $this->code = $code;
    }

    /**
     * @return array
     */
    public function toArray()
    {
        return [
            'data' => $this->data,
            'code' => $this->code,
            'message' => $this->message,
        ];
    }

    /**
     * @param int|string $offset
     * @return mixed
     */
    public function offsetExists($offset)
    {
        if ($offset == 'code' || $offset == 'message') {
            return true;
        }
        if ($offset == 'data') {
            return empty($this->data);
        }
        if ($this->prefix($offset)) {
            return false;
        }
        $data = $this->data();
        if (empty($data)) {
            return false;
        }
        return Arr::exists($data, $this->key($offset));
    }

    /**
     * @inheritDoc
     */
    public function offsetGet($offset)
    {
        if ($offset == 'code' || $offset == 'message' || $offset == 'data') {
            return $this->{$offset};
        }
        $data = $this->data();
        if (empty($data)) {
            return null;
        }
        if ($this->prefix($offset)) {
            return Arr::get($data, $this->key($offset));
        }
        return null;
    }

    /**
     * @inheritDoc
     */
    public function offsetSet($offset, $value)
    {
        if ($offset == 'code' || $offset == 'message' || $offset == 'data') {
            $this->{$offset} = $value;
        } else {
            if (!is_array($value) && empty($this->data)) {
                $this->data = [];
            }
            if ($this->prefix($offset)) {
                return Arr::set($this->data, $this->key($offset), $value);
            }
        }
        return null;
    }

    /**
     * @inheritDoc
     */
    public function offsetUnset($offset)
    {
        return;
    }

    public function code(): int
    {
        return (int)$this->code;
    }

    /**
     * 输出数据
     * @return array|null
     */
    public function data(): ?array
    {
        if (null === $this->data) {
            return null;
        }
        $data = $this->data;
        if (is_object($data) && $data instanceof Arrayable) {
            return $data->toArray();
        }
        if (!is_array($this->data)) {
            $this->data = ['value' => $this->data];
        }
        return $this->data;
    }

    /**
     * @return string
     */
    public function message(): string
    {
        return (string)$this->message;
    }

    /**
     * @param string $key
     * @return mixed|null
     */
    public function value(string $key)
    {
        $data = $this->data();
        if (empty($data) || !is_array($data)) {
            return null;
        }
        return Arr::get($data, $key);
    }

    /**
     * @param string $key
     * @return bool
     */
    protected function prefix(string $key): bool
    {
        return strpos($key, 'data.') === 0;
    }

    /**
     * key
     * @param $key
     * @return string
     */
    protected function key($key): string
    {
        return str_replace('data.', '', $key);
    }

    /**
     * 成功
     * @param $data
     * @param string $message
     * @param int $code
     * @return static
     */
    public static function success($data, $message = 'ok', $code = 200)
    {
        return new static($data, $message, $code);
    }

    /**
     * 失败
     * @param $message
     * @param int $code
     * @return static
     */
    public static function fail($message, $code = 400)
    {
        return new static(null, $message, $code);
    }

    /**
     * 异常
     * @param $err
     * @param int $code
     * @return static
     */
    public static function error($err, $code = 500)
    {
        if (is_string($err)) {
            return new static(null, $err, $code);
        }
        if ($err instanceof Throwable) {
            return new static(null, $err->getMessage(), $err->getCode());
        }
        return new static(null, 'error', $code);
    }

}
